using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Pool;

class GoPool
{
    public ObjectPool<GameObject> Pool { get; private set; }
    public readonly GameObject prefab;

    public GoPool(GameObject prefab)
    {
        this.prefab = prefab;
        Pool = new ObjectPool<GameObject>(CreatePooledItem, OnTakeFromPool, OnReturnedToPool, OnDestroyPoolObject);
    }

    private GameObject CreatePooledItem()
    {
        return Object.Instantiate(prefab);
    }

    // Called when an item is taken from the pool using Get
    protected virtual void OnTakeFromPool(GameObject obj)
    {
        obj.SetActive(true);
    }

    // Called when an item is returned to the pool using Release
    protected virtual void OnReturnedToPool(GameObject obj)
    {
        obj.SetActive(false);
    }

    // If the pool capacity is reached then any items returned will be destroyed.
    // We can control what the destroy behavior does, here we destroy the GameObject.
    private void OnDestroyPoolObject(GameObject obj)
    {
        Object.Destroy(obj);
    }
}

class GoPoolHideByPositon : GoPool
{
    readonly Vector3 MaxPosition = new Vector3(9999, 9999, 9999);
    public GoPoolHideByPositon(GameObject prefab) : base(prefab)
    {
    }

    protected override void OnReturnedToPool(GameObject obj)
    {
        obj.transform.position = MaxPosition;
    }

    protected override void OnTakeFromPool(GameObject obj)
    {
    }
}


public class PoolDict
{
    private readonly Dictionary<string, GoPool> poolDict = new();

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void InitPool(string type, GameObject prefab, bool isHideByPosition = false)
    {
#if UNITY_EDITOR
        if (poolDict.ContainsKey(type))
        {
            Debug.LogError($"Already init pool {type}");
            return;
        }
#endif
        if (isHideByPosition)
        {
            poolDict[type] = new GoPoolHideByPositon(prefab);
        }
        else
        {
            poolDict[type] = new GoPool(prefab);    
        }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public bool ContainPrefab(string goType)
    {
        return poolDict.ContainsKey(goType);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public GameObject Get(string type)
    {
#if UNITY_EDITOR
        if (!poolDict.ContainsKey(type))
        {
            Debug.LogError($"Not found pool of type {type}");
            return null;
        }
#endif
        return poolDict[type].Pool.Get();
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public GameObject GetPrefab(string type)
    {
        return poolDict[type].prefab;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Put(string type, GameObject go)
    {
#if UNITY_EDITOR
        if (!poolDict.ContainsKey(type))
        {
            Debug.LogError($"Not found pool of type {type}");
            return;
        }
#endif
        poolDict[type].Pool.Release(go);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void Clear()
    {
        foreach(var item in poolDict)
        {
            item.Value.Pool.Clear();
        }
        poolDict.Clear();
    }
}